#pragma once

#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <unistd.h>

#include "Thread.hpp"
#include "LockGuard.hpp"
#include "Log.hpp"

const int g_thread_num = 3;

template <class T>
class ThreadPool
{
private:
    ThreadPool(int thread_num = g_thread_num)
        : _num(thread_num)
    {
        pthread_mutex_init(&lock, nullptr);
        pthread_cond_init(&cond, nullptr);
        for(int i=1; i<=_num; i++)
        {
            _threads.push_back(new Thread(i, routine, this));
        }
    }
    ThreadPool(const ThreadPool<T> &other)=delete;
    const ThreadPool<T> &operator=(const ThreadPool<T> &other)=delete;
public:
    pthread_mutex_t* getMutex()
    {
        return &lock;
    }
    bool isEmpty()
    {
        return task_queue.empty();
    }
    void waitCond()
    {
        pthread_cond_wait(&cond, &lock);
    }
    T getTask()
    {
        T t=task_queue.front();
        task_queue.pop();
        return t;
    }
public:
    static ThreadPool<T>* getThreadPool(int num = g_thread_num)
    {
        if(nullptr==thread_ptr) 
        {
            lockGuard lockguard(&mutex);
            if (nullptr==thread_ptr)
            {
                thread_ptr=new ThreadPool<T>(num);
            }
        }
        return thread_ptr;
    }
    void run()
    {
        for(auto &iter : _threads)
        {
            iter->start();
            logMessage(NORMAL, "%s %s", iter->name().c_str(), "启动成功");
        }
    }
    static void* routine(void* args)
    {
        ThreadData* td=(ThreadData*)args;
        ThreadPool<T>* tp=(ThreadPool<T>*)td->_args;
        while(1)
        {
            T task;
            {
                lockGuard lockguard(tp->getMutex());
                while(tp->isEmpty())
                    tp->waitCond();
                task=tp->getTask();
            }
            task(td->_name);
        }
    }
    void pushTask(const T &task)
    {
        lockGuard lockguard(&lock);
        task_queue.push(task);
        pthread_cond_signal(&cond);
    }
    ~ThreadPool()
    {
        for(auto &iter : _threads)
        {
            iter->join();
            delete iter;
        }
        pthread_mutex_destroy(&lock);
        pthread_cond_destroy(&cond);
    }
private:
    std::vector<Thread*> _threads;
    int _num;
    std::queue<T> task_queue;
    static ThreadPool<T>* thread_ptr;
    static pthread_mutex_t mutex;
    pthread_mutex_t lock;
    pthread_cond_t cond;
};

template <typename T>
ThreadPool<T>* ThreadPool<T>::thread_ptr=nullptr;

template <typename T>
pthread_mutex_t ThreadPool<T>::mutex=PTHREAD_MUTEX_INITIALIZER;